home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / x / volume15 / olvwm-3.0 / part04 < prev    next >
Encoding:
Text File  |  1992-02-03  |  55.2 KB  |  2,068 lines

  1. Newsgroups: comp.sources.x
  2. Path: uunet!elroy.jpl.nasa.gov!ames!pasteur!nntp
  3. From: scott.oaks@East.Sun.COM (Scott Oaks)
  4. Subject: v15i150: OpenLook Virtual Window Mgr (3.0), Part04/21
  5. Message-ID: <1992Feb4.135516.6975@pasteur.Berkeley.EDU>
  6. Sender: dcmartin@msi.com (David C. Martin - Moderator)
  7. Nntp-Posting-Host: postgres.berkeley.edu
  8. Organization: University of California, at Berkeley
  9. References: <csx-15i147-olvwm-3.0@uunet.UU.NET>
  10. Date: Tue, 4 Feb 1992 13:55:16 GMT
  11. Approved: dcmartin@msi.com
  12.  
  13. Submitted-by: scott.oaks@East.Sun.COM (Scott Oaks)
  14. Posting-number: Volume 15, Issue 150
  15. Archive-name: olvwm-3.0/part04
  16.  
  17. # This is a shell archive.  Remove anything before this line, then feed it
  18. # into a shell via "sh file" or similar.  To overwrite existing files,
  19. # type "sh file -c".
  20. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  21. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  22. # If this archive is complete, you will see the following message at the end:
  23. #        "End of archive 4 (of 21)."
  24. # Contents:  Imakefile moveresize.c
  25. # Wrapped by dcmartin@fascet on Tue Jan 14 05:54:42 1992
  26. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  27. if test -f 'Imakefile' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'Imakefile'\"
  29. else
  30. echo shar: Extracting \"'Imakefile'\" \(3365 characters\)
  31. sed "s/^X//" >'Imakefile' <<'END_OF_FILE'
  32. X/**/# If you want to install the help files for olvwm, set HasInfoFiles to YES
  33. X#define HasInfoFiles    YES
  34. X
  35. X/**/# If you need the default menu file (you haven't installed OPENWINDOWS or
  36. X/**/# you haven't installed olwm) set NeedMenuFile to YES
  37. X#define NeedMenuFile    NO
  38. X
  39. X/**/# If you haven't installed olwm from xview3 or from Sun's OpenWindows,
  40. X/**/# and you want to install the olwm man page (which discusses most of the
  41. X/**/# window operations), defind NeedOlwmManPage to YES
  42. X#define NeedOlwmManPage    NO
  43. X
  44. X#undef DestDir
  45. X#define DestDir /auto/openwin
  46. X
  47. X/**/# No more changes needed
  48. X
  49. X#include <XView.tmpl>
  50. X
  51. X/**/#########################################################################
  52. X/**/# @(#)Imakefile    1.5 10/4/91 SMI
  53. X/**/# Imakefile for olwm release 3.0.
  54. X
  55. XDEFINES =  -DOW_I18N_L3 -DSUNDAE -DSHAPE
  56. XINCLUDES = -I$(HEADER_DEST) -I$(TOP)
  57. XSYS_LIBRARIES = -ll -lm
  58. XDEPLIBS = 
  59. XLOCAL_LIBRARIES = $(OLGXLIB) $(XLIB)
  60. X
  61. XHEADERS = cmdstream.h defaults.h environ.h events.h             \
  62. X      gettext.h globals.h group.h helpcmd.h i18n.h          \
  63. X      iconimage.h iconmask.h kbdfuncs.h list.h mem.h menu.h \
  64. X      notice.h olcursor.h olgx_impl.h ollocale.h olwm.h     \
  65. X      patchlevel.h properties.h resources.h screen.h slots.h\
  66. X      st.h virtual.h win.h
  67. X
  68. XINFOFILES = olvwm.info
  69. X#if NeedOlwmManPage
  70. XMANPAGES = olwm.man olvwmrc.man
  71. X#else
  72. XMANPAGES = olvwmrc.man
  73. X#endif
  74. XBITMAPS = iconbitmap.h
  75. XSCRIPTS = 
  76. XMISC     = openwin-menu
  77. X
  78. XSRCS    = Debug.c Error.c Notice.c Select.c WinInfo.c atom.c \
  79. X      client.c cmdstream.c defaults.c environ.c evbind.c \
  80. X      events.c gettext.c group.c helpsend.c images.c kbdfuncs.c \
  81. X      list.c mem.c menu.c moveresize.c ol_button.c olwm.c olvwmrc.c \
  82. X      properties.c resources.c screen.c services.c slave.c slots.c \
  83. X      st.c states.c usermenu.c usleep.c virtual.c win.c winbusy.c \
  84. X      winbutton.c wincolor.c winframe.c wingframe.c \
  85. X      winicon.c winipane.c winmenu.c winnofoc.c \
  86. X      winpane.c winpinmenu.c winpush.c winresize.c \
  87. X      winroot.c 
  88. X
  89. XOBJS =     \
  90. X      Debug.o Error.o Notice.o Select.o WinInfo.o atom.o \
  91. X          client.o cmdstream.o defaults.o environ.o evbind.o \
  92. X          events.o gettext.o group.o helpsend.o images.o kbdfuncs.o \ 
  93. X          list.o mem.o menu.o moveresize.o ol_button.o olwm.o olvwmrc.o \
  94. X      properties.o resources.o screen.o services.o slave.o slots.o \ 
  95. X          st.o states.o usermenu.o usleep.o version.o virtual.o win.o \
  96. X      winbusy.o winbutton.o wincolor.o winframe.o wingframe.o \ 
  97. X          winicon.o winipane.o winmenu.o winnofoc.o \ 
  98. X          winpane.o winpinmenu.o winpush.o winresize.o \ 
  99. X          winroot.o 
  100. X
  101. X
  102. XALLFILES = \
  103. X    ${HEADERS} ${BITMAPS} ${SRCS} \
  104. X    ${MISC} ${INFOFILES} ${MANPAGES} ${SCRIPTS}
  105. X
  106. XComplexProgramTarget(olvwm)
  107. X
  108. X#if NeedMenuFile
  109. XInstallNonExecList($(MISC),$(LIBRARY_DEST))
  110. X#endif
  111. X
  112. Xparse.c: parse.l
  113. X    lex -t parse.l > parse.c
  114. X
  115. Xolvwmrc.c: olvwmrc.y
  116. X    yacc olvwmrc.y
  117. X    mv y.tab.c olvwmrc.c
  118. X
  119. Xolvwmrc.o: parse.c olvwmrc.c
  120. X
  121. Xversion.c:: ${SRCS} ${HEADERS}
  122. X    @echo -n "#ident \"@(#)olvwm version compiled " > version.c
  123. X    @/bin/sh -c 'echo `date` \"' >> version.c
  124. X
  125. Xclean::
  126. X    /bin/rm -f parse.c olvwmrc.c version.c
  127. X
  128. Xinstall.man:: $(MANPAGES)
  129. X    @if [ -d $(DESTDIR)$(MANDIR) ]; then set +x; \
  130. X    else (set -x; $(MKDIRHIER) $(DESTDIR)$(MANDIR)); fi
  131. X    @for i in $(MANPAGES) ;\
  132. X    do \
  133. X    echo "installing $$i"; \
  134. X    $(INSTALL) -c $(INSTMANFLAGS) $$i $(DESTDIR)$(MANDIR)/`basename $$i .man`.$(MANSUFFIX) ; \
  135. X    done
  136. X
  137. X#include <XView.prog>
  138. END_OF_FILE
  139. if test 3365 -ne `wc -c <'Imakefile'`; then
  140.     echo shar: \"'Imakefile'\" unpacked with wrong size!
  141. fi
  142. # end of 'Imakefile'
  143. fi
  144. if test -f 'moveresize.c' -a "${1}" != "-c" ; then 
  145.   echo shar: Will not clobber existing file \"'moveresize.c'\"
  146. else
  147. echo shar: Extracting \"'moveresize.c'\" \(48613 characters\)
  148. sed "s/^X//" >'moveresize.c' <<'END_OF_FILE'
  149. X/*
  150. X *      (c) Copyright 1989 Sun Microsystems, Inc. Sun design patents
  151. X *      pending in the U.S. and foreign countries. See LEGAL_NOTICE
  152. X *      file for terms of the license.
  153. X */
  154. X
  155. X#ident "@(#)moveresize.c    1.1 olvwm version 1/3/92"
  156. X
  157. X/*
  158. X * Based on
  159. X#ident    "@(#)moveresize.c    26.37    91/09/14 SMI"
  160. X *
  161. X */
  162. X
  163. X#include <errno.h>
  164. X#include <stdio.h>
  165. X#include <string.h>
  166. X#include <X11/Xos.h>
  167. X#include <X11/Xlib.h>
  168. X#include <X11/Xutil.h>
  169. X#include <X11/keysym.h>
  170. X
  171. X#include "i18n.h"
  172. X#include "ollocale.h"
  173. X#include "mem.h"
  174. X#include "olwm.h"
  175. X#include "win.h"
  176. X#include "events.h"
  177. X#include "list.h"
  178. X#include "globals.h"
  179. X#include "group.h"
  180. X#include "virtual.h"
  181. X
  182. X/* REMIND - find out how to get rid of this */
  183. Xextern int Resize_width, Resize_height;
  184. X
  185. X#ifdef ALLPLANES
  186. Xextern int allplanes;
  187. X#endif
  188. X
  189. X
  190. Xtypedef enum {
  191. X    Unconstrained,        /* resizing not constrained */
  192. X    EitherConstrained,        /* constrained, but no direction yet */
  193. X    HorizConstrained,        /* constrained horizontally */
  194. X    VertConstrained,        /* constrained vertically */
  195. X} Constraint;
  196. X
  197. X
  198. X#define    DELTA_INCREASE        (1)
  199. X#define    DELTA_DECREASE        (-1)
  200. X#define    JUMP_INCREASE        (10)
  201. X#define    JUMP_DECREASE        (-10)
  202. X
  203. X#define REDUCE_ROUNDER        5
  204. X#define REDUCE_DIVIDER        10
  205. X
  206. X/*
  207. X * drawDouble
  208. X *
  209. X * Draw a thick box on the given window, using the given GC.  The box is drawn
  210. X * using four rectangles.  This technique is used instead of wide lines
  211. X * because this routine is used during animation, and the wide line code of
  212. X * some servers is too slow.
  213. X */
  214. X
  215. X#define defrect(r, X, Y, W, H) \
  216. X    (r).x = X, (r).y = Y, (r).width = W, (r).height = H
  217. X
  218. Xstatic void
  219. XdrawDouble(dpy, win, gc, x, y, w, h)
  220. X    Display    *dpy;
  221. X    Window      win;
  222. X    GC          gc;
  223. X    int         x, y, w, h;
  224. X{
  225. X    register int thick = GRV.RubberBandThickness;
  226. X    XRectangle  rects[4];
  227. X    int        nrects,doublethick;
  228. X
  229. X    if (w == 0 && h == 0)
  230. X    return;
  231. X
  232. X    doublethick = 2 * thick;
  233. X
  234. X    /* if too small for box just draw one solid rect */
  235. X    if (w <= doublethick || h <= doublethick) {
  236. X    defrect(rects[0], x, y, w, h);
  237. X    nrects = 1;
  238. X    /* else draw all 4 rects for the box */
  239. X    } else {
  240. X        defrect(rects[0], x, y, w, thick);
  241. X        defrect(rects[1], x, y + h - thick, w, thick);
  242. X        defrect(rects[2], x, y + thick, thick, h - doublethick);
  243. X        defrect(rects[3], x + w - thick, y + thick, thick, h - doublethick);
  244. X        nrects = 4;
  245. X    }
  246. X#ifdef ALLPLANES
  247. X    if (allplanes)
  248. X    XAllPlanesFillRectangles(dpy, win, rects, nrects);
  249. X    else
  250. X#endif /* ALLPLANES */
  251. X    XFillRectangles(dpy, win, gc, rects, nrects);
  252. X}
  253. X
  254. X#undef defrect
  255. X
  256. X
  257. X/* ===== status window ==================================================== */
  258. X
  259. X
  260. X#define HMARGIN 5
  261. X#define VMARGIN 3
  262. X
  263. X
  264. Xtypedef struct {
  265. X    Display    *dpy;
  266. X    Window    win;
  267. X    int        ypos;
  268. X    int        width;
  269. X    int        height;
  270. X    XFontStruct    *font;
  271. X    ScreenInfo    *scrinfo;
  272. X} StatusWinInfo;
  273. X
  274. X
  275. Xstatic StatusWinInfo *
  276. XcreateStatusWindow(dpy, scrinfo, proto)
  277. X    Display *dpy;
  278. X    ScreenInfo *scrinfo;
  279. X    char *proto;
  280. X{
  281. X    int width, height;
  282. X    XSetWindowAttributes attr;
  283. X    StatusWinInfo *sw;
  284. X    int    changed, x, y, w, h;
  285. X
  286. X    sw = MemNew(StatusWinInfo);
  287. X    sw->dpy = dpy;
  288. X    sw->font = GRV.TitleFontInfo;
  289. X    sw->height = sw->font->ascent + sw->font->descent + 2*VMARGIN;
  290. X    sw->width = XTextWidth(sw->font, proto, strlen(proto)) + 2*HMARGIN;
  291. X    sw->scrinfo = scrinfo;
  292. X
  293. X    if (MatchString(GRV.ResizePosition, "center")) {
  294. X    x = (DisplayWidth(dpy, scrinfo->screen) - sw->width) / 2;
  295. X    y = (DisplayHeight(dpy, scrinfo->screen) - sw->height) / 2;
  296. X    }
  297. X    else {
  298. X    changed = XParseGeometry(GRV.ResizePosition, &x, &y, &w, &h);
  299. X    if (changed & XValue)
  300. X        if (changed & XNegative)
  301. X        x = DisplayWidth(dpy, scrinfo->screen) + x;
  302. X        else ;
  303. X    else x = 0;
  304. X    if (changed & YValue)
  305. X        if (changed & YNegative)
  306. X        y = DisplayHeight(dpy, scrinfo->screen) + y;
  307. X        else ;
  308. X    else y = 0;
  309. X    }
  310. X
  311. X    attr.border_pixel = 0;
  312. X    attr.colormap = scrinfo->colormap;
  313. X    attr.save_under = True;
  314. X    sw->win = XCreateWindow(dpy, scrinfo->rootid, 
  315. X                x, y, sw->width, sw->height, 0,
  316. X                scrinfo->depth, InputOutput, scrinfo->visual,
  317. X                CWColormap | CWBorderPixel | CWSaveUnder, &attr);
  318. X    XMapRaised(dpy, sw->win);
  319. X    sw->ypos = VMARGIN + sw->font->ascent;
  320. X    return sw;
  321. X}
  322. X
  323. X
  324. Xstatic void
  325. XpaintStatusWindow(sw, string)
  326. X    StatusWinInfo *sw;
  327. X    char *string;
  328. X{
  329. X    if (sw == NULL)
  330. X    return;
  331. X
  332. X    olgx_draw_box(sw->scrinfo->gi[NORMAL_GINFO], sw->win, 0, 0,
  333. X          sw->width, sw->height, OLGX_NORMAL | OLGX_ERASE, True);
  334. X    
  335. X    XDrawString(sw->dpy, sw->win, sw->scrinfo->gc[FOREGROUND_GC], 
  336. X        (sw->width - XTextWidth(sw->font, string, strlen(string))) / 2,
  337. X        sw->ypos, string, strlen(string));
  338. X}
  339. X
  340. X
  341. Xstatic void
  342. XdestroyStatusWindow(sw)
  343. X    StatusWinInfo *sw;
  344. X{
  345. X    if (sw == NULL)
  346. X    return;
  347. X
  348. X    XDestroyWindow(sw->dpy, sw->win);
  349. X    MemFree(sw);
  350. X}
  351. X
  352. X
  353. X/* ===== mouse-based window moving ======================================== */
  354. X
  355. X
  356. Xtypedef struct {
  357. X    Display        *dpy;
  358. X    int            initX, initY;
  359. X    int            offX, offY;
  360. X    int            curX, curY;
  361. X    int            rounder, divider;
  362. X    List        *winlist;
  363. X    WinGenericFrame    *frame;
  364. X    StatusWinInfo    *statuswindow;
  365. X    Constraint        constraint;
  366. X    Bool        dragwin;        /* true=dragwin, false=dragframe */
  367. X    Bool        mouse;
  368. X    Bool        AutoRaise;        /* orig value of autoraise */
  369. X/*
  370. X * Virtual Desktop things
  371. X */
  372. X    int            check_vdm;
  373. X    int            vdm_screenX;
  374. X    int            vdm_screenY;
  375. X    int            inVDM;
  376. X    VirtualDesktop    *vdm;
  377. X    int            targetScreenX;
  378. X    int            targetScreenY;
  379. X    Region        region;
  380. X    Window        *children;
  381. X    int            num_children;
  382. X    int            vdm_stacking_order;
  383. X} MoveClosure;
  384. X
  385. X
  386. Xstatic Bool movewinInterposer();
  387. Xstatic void *moveOneWindow();
  388. Xstatic void *configOneWindow();
  389. Xstatic void *drawOneBox();
  390. Xstatic void moveDone();
  391. X
  392. X
  393. Xstatic void
  394. XmouseMovePaintStatus(mstuff, x, y)
  395. X    MoveClosure *mstuff;
  396. X    int x, y;
  397. X{
  398. X    char buf[50];
  399. X
  400. X    sprintf(buf, gettext("location: %d , %d"), x, y);
  401. X    paintStatusWindow(mstuff->statuswindow, buf);
  402. X}
  403. X
  404. Xstatic int
  405. XgetWindowStackingOrder(win, mstuff)
  406. X    Window    win;
  407. X    MoveClosure    *mstuff;
  408. X{
  409. Xint    i;
  410. X
  411. X    for (i = 0; i < mstuff->num_children; i++)
  412. X    if (mstuff->children[i] == win)
  413. X        return i;
  414. X    return 0;
  415. X}
  416. X
  417. Xstatic void *
  418. XmoveAddRegion(cli, mstuff)
  419. X    Client    *cli;
  420. X    MoveClosure    *mstuff;
  421. X
  422. X{
  423. XRegion        new;
  424. XXRectangle    rect;
  425. Xint        stacking_order;
  426. X
  427. X    if (!cli->framewin)
  428. X    return NULL;
  429. X    if (PANEWINOFCLIENT(cli) == PANEWINOFCLIENT(mstuff->vdm->client))
  430. X    return NULL;
  431. X    if (cli->screen != mstuff->vdm->client->screen)
  432. X    return NULL;
  433. X    switch(cli->wmState) {
  434. X    case IconicState:
  435. X        if (getWindowStackingOrder(cli->iconwin->core.self, mstuff) <
  436. X                mstuff->vdm_stacking_order)
  437. X        return NULL;
  438. X            rect.x = cli->iconwin->core.x;
  439. X            rect.y = cli->iconwin->core.y;
  440. X            rect.width = cli->iconwin->core.width;
  441. X            rect.height = cli->iconwin->core.height;
  442. X        break;
  443. X    case NormalState:
  444. X        if (getWindowStackingOrder(cli->framewin->core.self, mstuff) <
  445. X                mstuff->vdm_stacking_order)
  446. X        return NULL;
  447. X            rect.x = cli->framewin->core.x;
  448. X            rect.y = cli->framewin->core.y;
  449. X            rect.width = cli->framewin->core.width;
  450. X            rect.height = cli->framewin->core.height;
  451. X        break;
  452. X    default:
  453. X        return NULL;
  454. X    }
  455. X    new = XCreateRegion();
  456. X    XUnionRectWithRegion(rect, new, new);
  457. X    XSubtractRegion(mstuff->region, new, mstuff->region);
  458. X    XDestroyRegion(new);
  459. X    return NULL;
  460. X}
  461. X
  462. X/*
  463. X * UserMoveWindows
  464. X *
  465. X * Allow the user to move a window or the set of selected windows.  The
  466. X * "first" parameter must be the button event that initiated the interaction.  
  467. X * The "winInfo" parameter must be the frame or icon on which the action was 
  468. X * initiated.  The external boolean DragWindow controls whether the whole 
  469. X * window is moved or whether the outline is moved.
  470. X *
  471. X * TODO:
  472. X * (1) clean up coordinate systems;
  473. X * (2) implement hysteresis against other windows' edges.
  474. X */
  475. Xvoid
  476. XUserMoveWindows(cli, first)
  477. X    Client *cli;
  478. X    XEvent *first;
  479. X{
  480. X    Display *dpy = cli->dpy;
  481. X    List *winlist = NULL_LIST;
  482. X    static MoveClosure mstuff;
  483. X    Time     timestamp;
  484. X    XRectangle    rect;
  485. X    int        dummy;
  486. X
  487. X    {
  488. X    /*
  489. X     * Set up where the VDM is to allow/prevent moving into it
  490. X     */
  491. X    VirtualDesktop        *vdm;
  492. X    unsigned int    x, y, w, h, bw, d;
  493. X    Window        root;
  494. X
  495. X    vdm = cli->scrInfo->vdm;
  496. X    if (vdm && vdm->client->wmState != IconicState &&
  497. X        vdm->client != cli && GRV.AllowMoveIntoDesktop) {
  498. X        mstuff.check_vdm = True;
  499. X        XGetGeometry(dpy, vdm->client->framewin->core.self,
  500. X             &root, &x, &y, &w, &h, &bw, &d);
  501. X        mstuff.vdm_screenX = x;
  502. X        mstuff.vdm_screenY = y;
  503. X        XGetGeometry(dpy, vdm->client->framewin->fcore.panewin->core.self,
  504. X             &root, &x, &y, &w, &h, &bw, &d);
  505. X        mstuff.vdm_screenX += x;
  506. X        mstuff.vdm_screenY += y;
  507. X        mstuff.vdm = vdm;
  508. X        rect.x = mstuff.vdm_screenX;
  509. X        rect.y = mstuff.vdm_screenY;
  510. X        rect.width = w;
  511. X        rect.height = h;
  512. X    }
  513. X    else mstuff.check_vdm = False;
  514. X        mstuff.vdm = vdm;
  515. X    }
  516. X
  517. X    mstuff.dpy = dpy;
  518. X    mstuff.offX = 0;
  519. X    mstuff.offY = 0;
  520. X    mstuff.constraint = Unconstrained;
  521. X    mstuff.rounder = 0;
  522. X    mstuff.divider = 1;
  523. X    /*
  524. X     * Disable Autoraise while dragging -- otherwise, we obscure the moveresize
  525. X     * box
  526. X     */
  527. X    mstuff.AutoRaise = GRV.AutoRaise;
  528. X    GRV.AutoRaise = False;
  529. X    TimeoutCancel();
  530. X
  531. X    if (cli->wmState == IconicState)
  532. X    mstuff.frame = (WinGenericFrame *) cli->iconwin;
  533. X    else
  534. X    mstuff.frame = (WinGenericFrame *) cli->framewin;
  535. X
  536. X    if (first == NULL || first->type == KeyPress) {
  537. X    timestamp = (first == NULL) ? CurrentTime : first->xkey.time;
  538. X    mstuff.dragwin = False;
  539. X    mstuff.curX = mstuff.initX = mstuff.frame->core.x;
  540. X    mstuff.curY = mstuff.initY = mstuff.frame->core.y;
  541. X    mstuff.mouse = False;
  542. X    } else {
  543. X    /* it's a ButtonPress */
  544. X
  545. X    mstuff.curX = mstuff.initX = first->xbutton.x_root;
  546. X    mstuff.curY = mstuff.initY = first->xbutton.y_root;
  547. X    mstuff.dragwin = GRV.DragWindow;
  548. X    mstuff.mouse = True;
  549. X    timestamp = first->xbutton.time;
  550. X
  551. X    if (first->xbutton.state & ModMaskMap[MOD_INVERT])
  552. X        mstuff.dragwin = !mstuff.dragwin;
  553. X
  554. X    if (first->xbutton.state & ModMaskMap[MOD_REDUCE]) {
  555. X        mstuff.rounder = REDUCE_ROUNDER;
  556. X        mstuff.divider = REDUCE_DIVIDER;
  557. X    }
  558. X
  559. X    if (first->xbutton.state & ModMaskMap[MOD_CONSTRAIN])
  560. X        mstuff.constraint = EitherConstrained;
  561. X    }
  562. X    /*
  563. X     * This is esoteric: we don't want to allow a drag into an obscured
  564. X     * part of the VDM.  If we're dragging the outline, then it's easy,
  565. X     * since each event has the dest window, which will be the VDM only
  566. X     * when we want it to be.  If we're dragging the window, then the window
  567. X     * in the event will be the window's frame, and we have to have another
  568. X     * test to see if we're over an unobscured part of the VDM.
  569. X     *
  570. X     * The best I can come up with now is to create a region equal to the
  571. X     * unobscured part of the VDM.  This is probably very slow.
  572. X     */
  573. X    if (mstuff.check_vdm) {
  574. X        if (mstuff.dragwin) {
  575. X        mstuff.region = XCreateRegion();
  576. X        /* rect is set up above */
  577. X        XUnionRectWithRegion(rect, mstuff.region, mstuff.region);
  578. X        if (!XQueryTree(dpy, WinRootID(mstuff.frame), &dummy, &dummy,
  579. X               &mstuff.children, &mstuff.num_children))
  580. X        mstuff.num_children = 0;
  581. X        mstuff.vdm_stacking_order =
  582. X        getWindowStackingOrder(mstuff.vdm->client->framewin->core.self,
  583. X                    mstuff);
  584. X        ListApply(ActiveClientList, moveAddRegion, &mstuff);
  585. X    }
  586. X    else mstuff.region = NULL;
  587. X    }
  588. X
  589. X    /*
  590. X     * Generate the list of windows to be moved.  If the initial window is 
  591. X     * selected, we're moving the selection; otherwise, we're moving just this 
  592. X     * window.
  593. X     */
  594. X    if (IsSelected(cli)) {
  595. X    Client *c = (Client *) 0;
  596. X    int    allsticky = True;
  597. X
  598. X    while (c = EnumSelections(c)) {
  599. X        if (c->wmState == IconicState)
  600. X        winlist = ListCons(c->iconwin, winlist);
  601. X        else
  602. X        winlist = ListCons(c->framewin, winlist);
  603. X        /*
  604. X         * Can't move sticky windows into the VDM.  Thus, if all windows
  605. X         * is sticky, we don't allow any move into the VDM, since otherwise
  606. X         * its too confusing
  607. X         */
  608. X        allsticky = allsticky & !c->sticky;
  609. X    }
  610. X    if (allsticky)
  611. X        mstuff.check_vdm = False;
  612. X    } else {
  613. X    winlist = ListCons(mstuff.frame, NULL_LIST);
  614. X    if (cli->sticky)
  615. X        mstuff.check_vdm = False;
  616. X    }
  617. X    mstuff.winlist = winlist;
  618. X
  619. X    /* Grab the pointer to change the cursor and confine to the root window. */
  620. X
  621. X    if (XGrabPointer(dpy, cli->scrInfo->rootid, True,
  622. X             ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
  623. X             GrabModeAsync, GrabModeAsync, cli->scrInfo->rootid,
  624. X             GRV.MovePointer, timestamp) != GrabSuccess)
  625. X    {
  626. X    ErrorWarning(gettext("failed to grab pointer"));
  627. X    return;
  628. X    }
  629. X
  630. X    if (XGrabKeyboard(dpy, cli->scrInfo->rootid, False,
  631. X              GrabModeAsync, GrabModeAsync,
  632. X              timestamp) != GrabSuccess)
  633. X    {
  634. X    /* note: not fatal */
  635. X    ErrorWarning(gettext("failed to grab keyboard"));
  636. X    }
  637. X
  638. X    InstallInterposer(movewinInterposer, &mstuff);
  639. X
  640. X    if (GRV.ShowMoveGeometry)
  641. X    mstuff.statuswindow = createStatusWindow(dpy, cli->scrInfo,
  642. X                gettext("location: 0000 , 0000"));
  643. X    else
  644. X    mstuff.statuswindow = NULL;
  645. X
  646. X    /*
  647. X     * If we're dragging the outlines, we must also grab the server and draw 
  648. X     * the initial set of bounding boxes.
  649. X     */
  650. X    if (!mstuff.dragwin) {
  651. X    XGrabServer(dpy);
  652. X    (void) ListApply(mstuff.winlist, drawOneBox, &mstuff);
  653. X    }
  654. X}
  655. X
  656. X
  657. Xvoid
  658. XmoveUpdate(mstuff, event)
  659. X    MoveClosure *mstuff;
  660. X    XEvent    *event;
  661. X{
  662. X    if (!mstuff->dragwin)
  663. X    (void) ListApply(mstuff->winlist, drawOneBox, mstuff);
  664. X    
  665. X    if (mstuff->check_vdm && event) {
  666. X    if (!mstuff->region) {
  667. X        if (event->xmotion.window == PANEWINOFCLIENT(mstuff->vdm->client))
  668. X            mstuff->inVDM = True;
  669. X        /*
  670. X         * The events on the virtual windows are reported relative to
  671. X         * themselves; so if its a virtual window, we're in the VDM
  672. X         */
  673. X        else if (VGetInfo(event->xmotion.window))
  674. X            mstuff->inVDM = True;
  675. X        else if (mstuff->dragwin) {
  676. X            /*
  677. X             * If we're dragging the window and the event is on the window's
  678. X             * frame (ie we moved just a little) see if we're over the vdm.
  679. X             * If so, move into the vdm
  680. X             */
  681. X        }    
  682. X        else mstuff->inVDM = False;
  683. X    }
  684. X    else mstuff->inVDM = XPointInRegion(mstuff->region,
  685. X                event->xmotion.x_root, event->xmotion.y_root);
  686. X    }
  687. X    else mstuff->inVDM = False;
  688. X
  689. X    if (mstuff->inVDM) {
  690. X        mstuff->offX = (mstuff->curX - mstuff->vdm_screenX) *
  691. X            (mstuff->vdm->resources->scale / mstuff->divider) -
  692. X            mstuff->initX + mstuff->vdm->offsetX;
  693. X        mstuff->offY = (mstuff->curY - mstuff->vdm_screenY) *
  694. X            (mstuff->vdm->resources->scale / mstuff->divider) -
  695. X            mstuff->initY + mstuff->vdm->offsetY;
  696. X    }
  697. X    else {
  698. X        mstuff->offX =
  699. X        (mstuff->curX - mstuff->initX + mstuff->rounder) / mstuff->divider;
  700. X        mstuff->offY =
  701. X        (mstuff->curY - mstuff->initY + mstuff->rounder) / mstuff->divider;
  702. X    }
  703. X
  704. X    if (mstuff->constraint == EitherConstrained) {
  705. X    if (ABS(mstuff->offX) > ABS(mstuff->offY))
  706. X        mstuff->constraint = HorizConstrained;
  707. X    else
  708. X        mstuff->constraint = VertConstrained;
  709. X    }
  710. X
  711. X    if (mstuff->constraint == HorizConstrained) {
  712. X    mstuff->offY = 0;
  713. X    } else if (mstuff->constraint == VertConstrained) {
  714. X    mstuff->offX = 0;
  715. X    }
  716. X
  717. X    if (mstuff->dragwin)
  718. X    (void) ListApply(mstuff->winlist, moveOneWindow, mstuff);
  719. X    else
  720. X    (void) ListApply(mstuff->winlist, drawOneBox, mstuff);
  721. X}
  722. X
  723. X
  724. Xvoid
  725. XmoveKeyDelta(mstuff, dx, dy)
  726. X    MoveClosure *mstuff;
  727. X    int dx, dy;
  728. X{
  729. X    mstuff->constraint = Unconstrained;
  730. X
  731. X    if (mstuff->mouse) {
  732. X    mstuff->initX -= dx;
  733. X    mstuff->initY -= dy;
  734. X    } else {
  735. X    mstuff->curX += dx;
  736. X    mstuff->curY += dy;
  737. X    }
  738. X    moveUpdate(mstuff, NULL);
  739. X}
  740. X
  741. X
  742. X/*
  743. X * movewinInterposer
  744. X *
  745. X * Interposer function for moving windows.  Moves the list of windows on each 
  746. X * MotionNotify; releases interposition on ButtonRelease.
  747. X */
  748. X/*ARGSUSED*/
  749. Xstatic int
  750. XmovewinInterposer(dpy, event, w, mstuff)
  751. X    Display *dpy;
  752. X    XEvent *event;
  753. X    WinGeneric *w;
  754. X    MoveClosure *mstuff;
  755. X{
  756. X    XEvent nextevent;
  757. X    SemanticAction action;
  758. X
  759. X    switch (event->type) {
  760. X    case ButtonPress:
  761. X    /* ignore if buttons are already down */
  762. X    if (!FirstButtonDown(event))
  763. X        break;
  764. X
  765. X    switch (ResolveMouseBinding(dpy, event,
  766. X            ModMaskMap[MOD_REDUCE] | ModMaskMap[MOD_CONSTRAIN]))
  767. X    {
  768. X    case ACTION_SELECT:
  769. X        mstuff->mouse = True;
  770. X        mstuff->curX = event->xbutton.x_root;
  771. X        mstuff->curY = event->xbutton.y_root;
  772. X        mstuff->initX = mstuff->curX - mstuff->offX;
  773. X        mstuff->initY = mstuff->curY - mstuff->offY;
  774. X
  775. X        if (event->xbutton.state & ModMaskMap[MOD_REDUCE]) {
  776. X        mstuff->rounder = REDUCE_ROUNDER;
  777. X        mstuff->divider = REDUCE_DIVIDER;
  778. X        }
  779. X
  780. X        if (event->xbutton.state & ModMaskMap[MOD_CONSTRAIN])
  781. X        mstuff->constraint = EitherConstrained;
  782. X        break;
  783. X
  784. X    default:    /* otherwise, abort the move operation */
  785. X        mstuff->curX = mstuff->initX;
  786. X        mstuff->curY = mstuff->initY;
  787. X        moveUpdate(mstuff, event);
  788. X        moveDone(mstuff);
  789. X    }
  790. X    break;
  791. X
  792. X    case ButtonRelease:
  793. X    if (AllButtonsUp(event))
  794. X        moveDone(mstuff);
  795. X    break;
  796. X
  797. X    case MotionNotify:
  798. X    /* if the event is off the screen, ignore it */
  799. X        if (!event->xmotion.same_screen)
  800. X        break;
  801. X
  802. X    if (!mstuff->mouse)
  803. X        break;
  804. X
  805. X    /*
  806. X     * Motion compression.  If the next event is a MotionNotify,
  807. X     * ignore this one.
  808. X     */
  809. X    if (XEventsQueued(dpy, QueuedAfterReading) > 0 &&
  810. X        (XPeekEvent(dpy,&nextevent), nextevent.type == MotionNotify))
  811. X        break;
  812. X
  813. X    mstuff->curX = event->xmotion.x_root;
  814. X    mstuff->curY = event->xmotion.y_root;
  815. X    moveUpdate(mstuff, event);
  816. X    break;
  817. X
  818. X    case KeyPress:
  819. X    action = FindKeyboardAction(dpy, event);
  820. X
  821. X    switch (action) {
  822. X    case ACTION_UP:
  823. X        moveKeyDelta(mstuff,0,DELTA_DECREASE);
  824. X        break;
  825. X    case ACTION_DOWN:
  826. X        moveKeyDelta(mstuff,0,DELTA_INCREASE);
  827. X        break;
  828. X    case ACTION_LEFT:
  829. X        moveKeyDelta(mstuff,DELTA_DECREASE,0);
  830. X        break;
  831. X    case ACTION_RIGHT:
  832. X        moveKeyDelta(mstuff,DELTA_INCREASE,0);
  833. X        break;
  834. X    case ACTION_JUMP_UP:
  835. X        moveKeyDelta(mstuff,0,JUMP_DECREASE);
  836. X        break;
  837. X    case ACTION_JUMP_DOWN:
  838. X        moveKeyDelta(mstuff,0,JUMP_INCREASE);
  839. X        break;
  840. X    case ACTION_JUMP_LEFT:
  841. X        moveKeyDelta(mstuff,JUMP_DECREASE,0);
  842. X        break;
  843. X    case ACTION_JUMP_RIGHT:
  844. X        moveKeyDelta(mstuff,JUMP_INCREASE,0);
  845. X        break;
  846. X    case ACTION_EXEC_DEFAULT:
  847. X        moveDone(mstuff);
  848. X        break;
  849. X    case ACTION_STOP:
  850. X        mstuff->curX = mstuff->initX;
  851. X        mstuff->curY = mstuff->initY;
  852. X        moveUpdate(mstuff, NULL);
  853. X        moveDone(mstuff);
  854. X        break;
  855. X
  856. X    default:
  857. X        if (FindModifierMask(event->xkey.keycode) ==
  858. X        ModMaskMap[MOD_CONSTRAIN])
  859. X        {
  860. X        if (mstuff->mouse) {
  861. X            mstuff->constraint = EitherConstrained;
  862. X            moveUpdate(mstuff, NULL);
  863. X        }
  864. X        } else {
  865. X        KeyBeep(dpy, event);
  866. X        }
  867. X        break;
  868. X    }
  869. X    break;
  870. X
  871. X    case KeyRelease:
  872. X    if (FindModifierMask(event->xkey.keycode) ==
  873. X        ModMaskMap[MOD_CONSTRAIN])
  874. X    {
  875. X        mstuff->constraint = Unconstrained;
  876. X        moveUpdate(mstuff, NULL);
  877. X    }
  878. X    break;
  879. X
  880. X    /* Send out expose's immediately */
  881. X    case Expose:
  882. X    return DISPOSE_DISPATCH;
  883. X
  884. X    default:
  885. X    return DISPOSE_DEFER;
  886. X    }
  887. X
  888. X    return DISPOSE_USED;
  889. X}
  890. X
  891. X/* windowOff -- function to determine how far a window should be offset
  892. X * given a pointer offset.  Returns both X and Y, by reference.
  893. X */
  894. Xstatic void
  895. XwindowOff(win, mstuff, pox, poy)
  896. XWinGenericFrame *win;
  897. XMoveClosure *mstuff;
  898. Xint *pox, *poy;
  899. X{
  900. X    int pixw = DisplayWidth(win->core.client->dpy, win->core.client->screen);
  901. X    int hpoint;
  902. X    int pixy = DisplayHeight(win->core.client->dpy, win->core.client->screen);
  903. X
  904. X    if (mstuff->offX == 0)
  905. X    {
  906. X    *pox = 0;
  907. X    }
  908. X    else if (mstuff->offX > 0)
  909. X    {
  910. X        hpoint = pixw - win->core.x - win->core.width;
  911. X        if (!mstuff->inVDM && (mstuff->offX >= hpoint) &&
  912. X            (mstuff->offX <= hpoint + GRV.EdgeThreshold))
  913. X        *pox = hpoint;
  914. X    else {
  915. X        hpoint = mstuff->vdm->absoluteWidth + mstuff->vdm->offsetX -
  916. X                 win->core.x - win->core.width;
  917. X        if (mstuff->offX >= hpoint + win->core.width - Resize_width)
  918. X            *pox = hpoint + win->core.width - Resize_width;
  919. X        else
  920. X            *pox = mstuff->offX;
  921. X    }
  922. X    }
  923. X    else if (mstuff->offX < 0)
  924. X    {
  925. X        if (!mstuff->inVDM && (mstuff->offX <= -win->core.x) &&
  926. X            (mstuff->offX >= (-win->core.x - GRV.EdgeThreshold)))
  927. X        *pox = -win->core.x;
  928. X    else if (mstuff->offX <= (-win->core.x - win->core.width +
  929. X            Resize_width + mstuff->vdm->offsetX))
  930. X        *pox = (-win->core.x - win->core.width +
  931. X            Resize_width + mstuff->vdm->offsetX);
  932. X    else
  933. X        *pox = mstuff->offX;
  934. X    }
  935. X
  936. X    if (mstuff->offY == 0)
  937. X    {
  938. X    *poy = 0;
  939. X    }
  940. X    else if (mstuff->offY > 0)
  941. X    {
  942. X        hpoint = pixy - win->core.y - win->core.height;
  943. X        if (!mstuff->inVDM && (mstuff->offY >= hpoint) &&
  944. X            (mstuff->offY <= hpoint + GRV.EdgeThreshold))
  945. X        *poy = hpoint;
  946. X    else {
  947. X        hpoint = mstuff->vdm->absoluteHeight + mstuff->vdm->offsetY -
  948. X            win->core.y - win->core.height;
  949. X        if (mstuff->offY >= hpoint + win->core.height - Resize_height)
  950. X            *poy = hpoint + win->core.height - Resize_height;
  951. X        else
  952. X            *poy = mstuff->offY;
  953. X    }
  954. X    }
  955. X    else if (mstuff->offY < 0)
  956. X    {
  957. X        if (!mstuff->inVDM && (mstuff->offY <= -win->core.y) &&
  958. X            (mstuff->offY >= (-win->core.y - GRV.EdgeThreshold)))
  959. X        *poy = -win->core.y;
  960. X    else if (mstuff->offY <= (-win->core.y - win->core.height +
  961. X            Resize_height + mstuff->vdm->offsetY))
  962. X        *poy = (-win->core.y - win->core.height + Resize_height +
  963. X            mstuff->vdm->offsetY);
  964. X    else
  965. X        *poy = mstuff->offY;
  966. X    }
  967. X}
  968. X
  969. X/*
  970. X * moveOneWindow
  971. X *
  972. X * Apply function for window moving animation.  Draws a window outline or 
  973. X * actually moves the window, depending on DragWindow.
  974. X */
  975. Xstatic void *
  976. XmoveOneWindow(win, mstuff)
  977. X    WinGenericFrame *win;
  978. X    MoveClosure *mstuff;
  979. X{
  980. X    int offX, offY;
  981. X
  982. X    windowOff(win, mstuff, &offX, &offY);
  983. X    XMoveWindow(mstuff->dpy, win->core.self,
  984. X        win->core.x + offX,
  985. X        win->core.y + offY);
  986. X    XMoveWindow(mstuff->dpy, win->core.virtual,
  987. X        (win->core.x + offX - mstuff->vdm->offsetX) /
  988. X                mstuff->vdm->resources->scale,
  989. X        (win->core.y + offY - mstuff->vdm->offsetY) /
  990. X                mstuff->vdm->resources->scale);
  991. X    if (win == mstuff->frame)
  992. X    mouseMovePaintStatus(mstuff, win->core.x + offX, win->core.y + offY);
  993. X    return (void *) 0;
  994. X}
  995. X
  996. X
  997. X/*
  998. X * drawOneBox
  999. X *
  1000. X * Apply function for drawing XOR boxes.  Draws a double-width rectangle 
  1001. X * around the outline of a single window.
  1002. X */
  1003. Xstatic void *
  1004. XdrawOneBox(w, mstuff)
  1005. X    WinGenericFrame *w;
  1006. X    MoveClosure *mstuff;
  1007. X{
  1008. X    int offX, offY;
  1009. X
  1010. X    windowOff(w, mstuff, &offX, &offY);
  1011. X    drawDouble(mstuff->dpy, w->core.client->scrInfo->rootid, WinGC(w,ROOT_GC),
  1012. X           w->core.x + offX, w->core.y + offY,
  1013. X           w->core.width, w->core.height);
  1014. X    drawDouble(mstuff->dpy, PANEWINOFCLIENT(mstuff->vdm->client),
  1015. X        WinGC(w, ROOT_GC),
  1016. X        (w->core.x + offX - mstuff->vdm->offsetX) /
  1017. X                mstuff->vdm->resources->scale,
  1018. X        (w->core.y + offY - mstuff->vdm->offsetY) /
  1019. X                mstuff->vdm->resources->scale,
  1020. X        w->core.width / mstuff->vdm->resources->scale,
  1021. X        w->core.height / mstuff->vdm->resources->scale);
  1022. X
  1023. X    if (w == mstuff->frame)
  1024. X    mouseMovePaintStatus(mstuff, w->core.x + offX, w->core.y + offY);
  1025. X
  1026. X    return (void *) 0;
  1027. X}    
  1028. X
  1029. X
  1030. X/*
  1031. X * doconfigOneWindow
  1032. X *
  1033. X * Apply function for calling a moved window's configfunc.
  1034. X *
  1035. X */
  1036. Xstatic void *
  1037. XdoConfigOneWindow(win, mstuff)
  1038. X    WinGenericFrame *win;
  1039. X    MoveClosure *mstuff;
  1040. X{
  1041. X    int offX, offY;
  1042. X    int    dw, dh;
  1043. X
  1044. X    if (ListIsAMember(win, mstuff->winlist)) {
  1045. X        windowOff(win, mstuff, &offX, &offY);
  1046. X        GFrameSetConfig(win, win->core.x + offX, win->core.y + offY,
  1047. X                win->core.width, win->core.height);
  1048. X    }
  1049. X    else {
  1050. X    /* Else we're moving a dependent window without having selected it --
  1051. X     * ie VirtualMoveGroup is True and we're moving into the VDM.  So
  1052. X     * keep the relative screen position of this window
  1053. X     */
  1054. X    dw = DisplayWidth(win->core.client->dpy, win->core.client->screen);
  1055. X    dh = DisplayHeight(win->core.client->dpy, win->core.client->screen);
  1056. X    offX = mstuff->targetScreenX * dw + mstuff->vdm->offsetX;
  1057. X    offY = mstuff->targetScreenY * dh + mstuff->vdm->offsetY;
  1058. X        GFrameSetConfig(win, (win->core.x % dw) + offX, (win->core.y % dh) + offY,
  1059. X                win->core.width, win->core.height);
  1060. X    }
  1061. X    if (GRV.VirtualRaiseOnMove)
  1062. X    RaiseWindow(win);
  1063. X    return (void *) 0;
  1064. X}
  1065. X
  1066. Xstatic void *
  1067. XconfigOneClient(cli, mstuff)
  1068. X    Client    *cli;
  1069. X    MoveClosure    *mstuff;
  1070. X
  1071. X{
  1072. X    doConfigOneWindow(cli->framewin, mstuff);
  1073. X    doConfigOneWindow(cli->iconwin, mstuff);
  1074. X    cli->flags |= CLMoved;
  1075. X    return (void *) 0;
  1076. X}
  1077. X
  1078. Xstatic void *
  1079. XconfigOneWindow(win, mstuff)
  1080. X    WinGenericFrame *win;
  1081. X    MoveClosure *mstuff;
  1082. X{
  1083. Xint    dw, dh;
  1084. Xint     offX, offY;
  1085. Xint    newScreenX, curScreenX,    newScreenY, curScreenY;
  1086. Xint    width, height;
  1087. XClient    *leader;
  1088. X
  1089. X    if (win->core.client->flags & CLMoved)
  1090. X    return (void *) 0;
  1091. X    dw = DisplayWidth(win->core.client->dpy, win->core.client->screen);
  1092. X    dh = DisplayHeight(win->core.client->dpy, win->core.client->screen);
  1093. X    windowOff(win, mstuff, &offX, &offY);
  1094. X    width = win->core.width;
  1095. X    height = win->core.height;
  1096. X    if (GRV.VirtualMoveGroups) {
  1097. X    switch(win->core.client->groupmask) {
  1098. X        case GROUP_LEADER:
  1099. X        leader = win->core.client;
  1100. X        break;
  1101. X        case GROUP_DEPENDENT:
  1102. X            leader = GroupLeader(win->core.client->groupid);
  1103. X        if (!leader) {
  1104. X            doConfigOneWindow(win, mstuff);
  1105. X            return (void *) 0;
  1106. X        }
  1107. X        break;
  1108. X        case GROUP_INDEPENDENT:
  1109. X        doConfigOneWindow(win, mstuff);
  1110. X        return (void *) 0;
  1111. X    }
  1112. X    curScreenX = (win->core.x - mstuff->vdm->offsetX) / dw;
  1113. X    if (offX < 0)
  1114. X        newScreenX = (win->core.x + offX + mstuff->vdm->offsetX) / dw;
  1115. X    else newScreenX = (win->core.x + offX - mstuff->vdm->offsetX) / dw;
  1116. X    mstuff->targetScreenX = newScreenX;
  1117. X    curScreenY = (win->core.y - mstuff->vdm->offsetY) / dh;
  1118. X    if (offY < 0)
  1119. X        newScreenY = (win->core.y + offY + mstuff->vdm->offsetY) / dh;
  1120. X    else newScreenY = (win->core.y + offY - mstuff->vdm->offsetY) / dh;
  1121. X    mstuff->targetScreenY = newScreenY;- curScreenY;
  1122. X    if (curScreenX - newScreenX == 0 && curScreenY - newScreenY == 0)
  1123. X        doConfigOneWindow(win, mstuff);
  1124. X    else GroupApply(leader->groupid, configOneClient, mstuff,
  1125. X            GROUP_LEADER | GROUP_DEPENDENT);
  1126. X    }
  1127. X    else doConfigOneWindow(win, mstuff);
  1128. X    return (void *) 0;
  1129. X}
  1130. X
  1131. Xstatic void *
  1132. XdoConfigOneClientCleanup(cli)
  1133. X    Client    *cli;
  1134. X
  1135. X{
  1136. X    cli->flags &= ~CLMoved;
  1137. X    return (void *) 0;
  1138. X}
  1139. X
  1140. Xstatic void *
  1141. XconfigOneWindowCleanup(win)
  1142. X    WinGeneric    *win;
  1143. X{
  1144. XClient    *leader;
  1145. X
  1146. X    if (GRV.VirtualMoveGroups) {
  1147. X    leader = GroupLeader(win->core.client->groupid);
  1148. X    if (!leader) {
  1149. X        doConfigOneClientCleanup(win->core.client);
  1150. X        return (void *) 0;
  1151. X    }
  1152. X    GroupApply(leader->groupid, doConfigOneClientCleanup, 0,
  1153. X            GROUP_LEADER | GROUP_DEPENDENT);
  1154. X    }
  1155. X    else win->core.client->flags &= ~CLMoved;
  1156. X    return (void *) 0;
  1157. X}
  1158. X
  1159. X/*
  1160. X * moveDone
  1161. X *
  1162. X * Cleanup function for window moving.  Releases grabs, uninstalls 
  1163. X * interposition, cleans up.
  1164. X */
  1165. Xstatic void
  1166. XmoveDone(mstuff)
  1167. X    MoveClosure *mstuff;
  1168. X{
  1169. X    /*
  1170. X     * If we're dragging the outlines, we must ungrab the server and undraw 
  1171. X     * the last set of boxes.
  1172. X     */
  1173. X    if (!mstuff->dragwin) {
  1174. X    (void) ListApply(mstuff->winlist, drawOneBox, mstuff);
  1175. X    XUngrabServer(mstuff->dpy);
  1176. X    }
  1177. X    UninstallInterposer();
  1178. X    XUngrabPointer(mstuff->dpy, CurrentTime);
  1179. X    XUngrabKeyboard(mstuff->dpy, CurrentTime);
  1180. X
  1181. X    (void) ListApply(mstuff->winlist, configOneWindow, mstuff);
  1182. X    (void) ListApply(mstuff->winlist, configOneWindowCleanup, 0);
  1183. X    ListDestroy(mstuff->winlist);
  1184. X    if (mstuff->region) {
  1185. X    XDestroyRegion(mstuff->region);
  1186. X    if (mstuff->num_children)
  1187. X        XFree(mstuff->children);
  1188. X    }
  1189. X
  1190. X    destroyStatusWindow(mstuff->statuswindow);
  1191. X    GRV.AutoRaise = mstuff->AutoRaise;
  1192. X}
  1193. X
  1194. X
  1195. X/* ===== mouse-based resizing ============================================= */
  1196. X
  1197. X
  1198. X/*
  1199. X * Note on use of gravity values: in this section, the gravity field is used 
  1200. X * to denote the window edge or corner that is being moved.  It's not
  1201. X * being used as "gravity" in the usual sense, which is the location that is 
  1202. X * being held constant.
  1203. X *
  1204. X * TODO:
  1205. X * (1) implement screen edge hysteresis for resize+move mode (meta key);
  1206. X * (2) implement window edge hysteresis.
  1207. X */
  1208. X
  1209. X/*
  1210. X * The following enum is arranged specifically so that the values can be 
  1211. X * tested with bit operations.  The one-bit indicates down or right if one, up 
  1212. X * or left if zero.  The two-bit indicates vertical if one, horizontal if zero.
  1213. X * The four-bit indicates a jump if one, normal if zero.
  1214. X */
  1215. Xtypedef enum {
  1216. X    RS_LEFT = 0,
  1217. X    RS_RIGHT,
  1218. X    RS_UP,
  1219. X    RS_DOWN,
  1220. X    RS_J_LEFT,
  1221. X    RS_J_RIGHT,
  1222. X    RS_J_UP,
  1223. X    RS_J_DOWN
  1224. X} ResizeAction;
  1225. X
  1226. X#define RS_ISRIGHT        (1<<0)
  1227. X#define RS_ISDOWN        (1<<0)
  1228. X#define RS_ISVERT        (1<<1)
  1229. X#define RS_ISJUMP        (1<<2)
  1230. X
  1231. X#define RS_JUMPMULT        10            /* jump multiplier */
  1232. X
  1233. Xstruct {
  1234. X    int x, y;
  1235. X} ResizeDeltas[] = {
  1236. X    {           -1,            0 },    /* left */
  1237. X    {            1,            0 },    /* right */
  1238. X    {            0,           -1 },    /* up */
  1239. X    {            0,            1 },    /* down */
  1240. X    { -RS_JUMPMULT,            0 },    /* jump left */
  1241. X    {  RS_JUMPMULT,            0 },    /* jump right */
  1242. X    {            0, -RS_JUMPMULT },    /* jump up */
  1243. X    {            0,  RS_JUMPMULT }    /* jump down */
  1244. X};
  1245. X
  1246. X
  1247. Xtypedef struct {
  1248. X    Client        *cli;
  1249. X    Constraint        constraint;
  1250. X    Bool        drawn;
  1251. X    Bool        moving;
  1252. X    Bool        minAspect, maxAspect;
  1253. X    Bool        baseProvided;
  1254. X    int            origX, origY;
  1255. X    int            curX, curY;    /* current mouse position */
  1256. X    int            winX, winY;    /* current window position */
  1257. X    int            winW, winH;    /* current window height */
  1258. X    int            minW, minH;
  1259. X    int            maxW, maxH;
  1260. X    int            incW, incH;
  1261. X    int            minAspectX, minAspectY;
  1262. X    int            maxAspectX, maxAspectY;
  1263. X    int            baseW, baseH;
  1264. X    int            borderW, borderH;   /* size of frame border */
  1265. X    void        (*callback)();
  1266. X    void        *cbarg;
  1267. X    StatusWinInfo    *statuswindow;
  1268. X    int            gravity;        /* see note above */
  1269. X    Bool        mouse;            /* using mouse? */
  1270. X} ResizeClosure;
  1271. X
  1272. X
  1273. X/*
  1274. X * Macro for adjusting the size of a window to its resize increment.  First,
  1275. X * assigns diff to be the difference between the size and the next lesser
  1276. X * incremental size.  If diff is greater than half the incremental
  1277. X * size, adjust the size upward to the next greater increment, otherwise 
  1278. X * adjust downward.  THIS MACRO ALTERS ITS FIRST ARGUMENT.
  1279. X *
  1280. X * size is the window size to be adjusted
  1281. X * base is base size, to be subtracted off before modulo is done
  1282. X * i is the incremental size
  1283. X */
  1284. X#define INCADJ(size, base, i)                        \
  1285. X    {                                    \
  1286. X    int diff;                            \
  1287. X    diff = ((size) - (base)) % (i);                    \
  1288. X    (size) += (diff > (i)/2) ? (i)-diff : -diff;            \
  1289. X    }
  1290. X
  1291. X
  1292. Xstatic void
  1293. XresizeDraw(rstuff)
  1294. X    ResizeClosure *rstuff;
  1295. X{
  1296. X    drawDouble(rstuff->cli->dpy, WinRootID(rstuff->cli->framewin),
  1297. X           WinGC(rstuff->cli->framewin, ROOT_GC),
  1298. X           rstuff->winX, rstuff->winY, rstuff->winW, rstuff->winH);
  1299. X    drawDouble(rstuff->cli->dpy,
  1300. X        PANEWINOFCLIENT(rstuff->cli->scrInfo->vdm->client),
  1301. X        WinGC(rstuff->cli->framewin, ROOT_GC),
  1302. X        rstuff->winX / rstuff->cli->scrInfo->vdm->resources->scale,
  1303. X        rstuff->winY / rstuff->cli->scrInfo->vdm->resources->scale,
  1304. X        rstuff->winW / rstuff->cli->scrInfo->vdm->resources->scale,
  1305. X        rstuff->winH / rstuff->cli->scrInfo->vdm->resources->scale);
  1306. X}
  1307. X
  1308. X
  1309. Xstatic void
  1310. XresizePaintStatus(rstuff)
  1311. X    ResizeClosure *rstuff;
  1312. X{
  1313. X    char buf[30];
  1314. X    int w, h;
  1315. X
  1316. X    w = rstuff->winW - rstuff->borderW;
  1317. X    h = rstuff->winH - rstuff->borderH;
  1318. X
  1319. X    if (rstuff->baseProvided) {
  1320. X    w -= rstuff->baseW;
  1321. X    h -= rstuff->baseH;
  1322. X    }
  1323. X    
  1324. X    sprintf(buf, gettext("size: %d x %d"), w / rstuff->incW, h / rstuff->incH);
  1325. X    paintStatusWindow(rstuff->statuswindow, buf);
  1326. X}
  1327. X
  1328. X
  1329. Xstatic void
  1330. XresizeDone(dpy, e, w, rstuff, doit)
  1331. X    Display *dpy;
  1332. X    XEvent *e;
  1333. X    WinGeneric *w;
  1334. X    ResizeClosure *rstuff;
  1335. X    Bool doit;
  1336. X{
  1337. X    if (rstuff->drawn)
  1338. X    resizeDraw(rstuff);
  1339. X
  1340. X    UninstallInterposer();
  1341. X    XUngrabPointer(dpy, e->xbutton.time);
  1342. X    XUngrabKeyboard(dpy, e->xbutton.time);
  1343. X    XUngrabServer(dpy);
  1344. X
  1345. X    if (doit)
  1346. X    GFrameSetConfig(rstuff->cli->framewin, rstuff->winX, rstuff->winY,
  1347. X            rstuff->winW, rstuff->winH);
  1348. X
  1349. X    if (rstuff->callback != NULL)
  1350. X    (*rstuff->callback)(dpy, rstuff->cbarg);
  1351. X
  1352. X    destroyStatusWindow(rstuff->statuswindow);
  1353. X}
  1354. X
  1355. X
  1356. Xstatic void
  1357. XresizeMotion(rstuff, x, y)
  1358. X    ResizeClosure *rstuff;
  1359. X    int x, y;
  1360. X{
  1361. X    int dx, dy, dW, dH, newW, newH;
  1362. X
  1363. X    dx = x - rstuff->curX;
  1364. X    dy = y - rstuff->curY;
  1365. X
  1366. X    if (ABS(dx) <= GRV.MoveThreshold && ABS(dy) <= GRV.MoveThreshold &&
  1367. X    !rstuff->drawn)
  1368. X    return;
  1369. X    
  1370. X    if (rstuff->mouse) {
  1371. X    if (rstuff->constraint == EitherConstrained) {
  1372. X        if (ABS(rstuff->origX - x) > ABS(rstuff->origY - y))
  1373. X        rstuff->constraint = HorizConstrained;
  1374. X        else
  1375. X        rstuff->constraint = VertConstrained;
  1376. X    }
  1377. X
  1378. X    if (rstuff->constraint == HorizConstrained) {
  1379. X        y = rstuff->origY;
  1380. X        dy = y - rstuff->curY;
  1381. X    } else if (rstuff->constraint == VertConstrained) {
  1382. X        x = rstuff->origX;
  1383. X        dx = x - rstuff->curX;
  1384. X    }
  1385. X    }
  1386. X
  1387. X    newW = rstuff->winW;
  1388. X    newH = rstuff->winH;
  1389. X    if (rstuff->moving) {
  1390. X    if (dx == 0 && dy == 0)
  1391. X        return;
  1392. X    if (rstuff->drawn)
  1393. X        resizeDraw(rstuff);
  1394. X    rstuff->winX += dx;
  1395. X    rstuff->winY += dy;
  1396. X    rstuff->curX += dx;
  1397. X    rstuff->curY += dy;
  1398. X    resizeDraw(rstuff);
  1399. X    rstuff->drawn = True;
  1400. X    return;
  1401. X    }
  1402. X
  1403. X    switch (rstuff->gravity) {
  1404. X    case NorthWestGravity:
  1405. X    newW -= dx;
  1406. X    newH -= dy;
  1407. X    break;
  1408. X    case NorthGravity:
  1409. X    newH -= dy;
  1410. X    break;
  1411. X    case NorthEastGravity:
  1412. X    newW += dx;
  1413. X    newH -= dy;
  1414. X    break;
  1415. X    case WestGravity:
  1416. X    newW -= dx;
  1417. X    break;
  1418. X    case CenterGravity:
  1419. X    break;
  1420. X    case EastGravity:
  1421. X    newW += dx;
  1422. X    break;
  1423. X    case SouthWestGravity:
  1424. X    newW -= dx;
  1425. X    newH += dy;
  1426. X    break;
  1427. X    case SouthGravity:
  1428. X    newH += dy;
  1429. X    break;
  1430. X    case SouthEastGravity:
  1431. X    newW += dx;
  1432. X    newH += dy;
  1433. X    break;
  1434. X    }
  1435. X
  1436. X    /*
  1437. X     * Convert from frame size to pane size, apply the constraints, then 
  1438. X     * convert back to frame size.
  1439. X     */
  1440. X
  1441. X    newW -= rstuff->borderW;
  1442. X    newH -= rstuff->borderH;
  1443. X
  1444. X    INCADJ(newW, rstuff->baseW, rstuff->incW);
  1445. X    INCADJ(newH, rstuff->baseH, rstuff->incH);
  1446. X
  1447. X    newW = MAX(rstuff->minW, MIN(rstuff->maxW, newW));
  1448. X    newH = MAX(rstuff->minH, MIN(rstuff->maxH, newH));
  1449. X
  1450. X    if (rstuff->maxAspect &&
  1451. X    newW * rstuff->maxAspectY > newH * rstuff->maxAspectX)
  1452. X    {
  1453. X    if (rstuff->maxAspectX > rstuff->maxAspectY) {
  1454. X        /* max aspect is wider than tall; increase height. */
  1455. X        newH = (newW * rstuff->maxAspectY) / rstuff->maxAspectX;
  1456. X        if (newH > rstuff->maxH) {
  1457. X        newH = rstuff->maxH;
  1458. X        newW = (newH * rstuff->maxAspectX) / rstuff->maxAspectY;
  1459. X        }
  1460. X    } else {
  1461. X        /* max aspect is taller than wide; decrease width. */
  1462. X        newW = (newH * rstuff->maxAspectX) / rstuff->maxAspectY;
  1463. X        if (newW < rstuff->minW) {
  1464. X        newW = rstuff->minW;
  1465. X        newH = (newW * rstuff->maxAspectY) / rstuff->maxAspectX;
  1466. X        }
  1467. X    }
  1468. X    }
  1469. X
  1470. X    if (rstuff->minAspect &&
  1471. X    newW * rstuff->minAspectY < newH * rstuff->minAspectX)
  1472. X    {
  1473. X    if (rstuff->minAspectX > rstuff->minAspectY) {
  1474. X        /* min aspect is wider than tall; decrease height. */
  1475. X        newH = (newW * rstuff->minAspectY) / rstuff->minAspectX;
  1476. X        if (newH < rstuff->minH) {
  1477. X        newH = rstuff->minH;
  1478. X        newW = (newH * rstuff->minAspectX) / rstuff->minAspectY;
  1479. X        }
  1480. X    } else {
  1481. X        /* min aspect is taller than wide; increase width. */
  1482. X        newW = (newH * rstuff->minAspectX) / rstuff->minAspectY;
  1483. X        if (newW > rstuff->maxW) {
  1484. X        newW = rstuff->maxW;
  1485. X        newH = (newW * rstuff->minAspectY) / rstuff->minAspectX;
  1486. X        }
  1487. X    }
  1488. X    }
  1489. X
  1490. X    newW += rstuff->borderW;
  1491. X    newH += rstuff->borderH;
  1492. X
  1493. X    /*
  1494. X     * Calculate the change in size (if any) and update the window's origin
  1495. X     * (winX, winY) depending on which corner is being moved.  Also, update
  1496. X     * the virtual pointer location (curX, curY).  Don't draw anything if the
  1497. X     * size hasn't changed.
  1498. X     */
  1499. X
  1500. X    dW = newW - rstuff->winW;
  1501. X    dH = newH - rstuff->winH;
  1502. X
  1503. X    if (dW == 0 && dH == 0)
  1504. X    return;
  1505. X
  1506. X    if (rstuff->drawn)
  1507. X    resizeDraw(rstuff);
  1508. X
  1509. X    switch (rstuff->gravity) {
  1510. X    case NorthWestGravity:
  1511. X    rstuff->winX -= dW;
  1512. X    rstuff->winY -= dH;
  1513. X    rstuff->curX -= dW;
  1514. X    rstuff->curY -= dH;
  1515. X    break;
  1516. X    case NorthGravity:
  1517. X    rstuff->winX -= dW / 2;
  1518. X    rstuff->winY -= dH;
  1519. X    rstuff->curY -= dH;
  1520. X    break;
  1521. X    case NorthEastGravity:
  1522. X    rstuff->winY -= dH;
  1523. X    rstuff->curX += dW;
  1524. X    rstuff->curY -= dH;
  1525. X    break;
  1526. X    case WestGravity:
  1527. X    rstuff->winX -= dW;
  1528. X    rstuff->winY -= dH / 2;
  1529. X    rstuff->curX -= dW;
  1530. X    break;
  1531. X    case CenterGravity:
  1532. X    rstuff->winX -= dW / 2;
  1533. X    rstuff->winY -= dH / 2;
  1534. X    break;
  1535. X    case EastGravity:
  1536. X    rstuff->winY -= dH / 2;
  1537. X    rstuff->curX += dW;
  1538. X    break;
  1539. X    case SouthWestGravity:
  1540. X    rstuff->winX -= dW;
  1541. X    rstuff->curX -= dW;
  1542. X    rstuff->curY += dH;
  1543. X    break;
  1544. X    case SouthGravity:
  1545. X    rstuff->winX -= dW / 2;
  1546. X    rstuff->curY += dH;
  1547. X    break;
  1548. X    case SouthEastGravity:
  1549. X    rstuff->curX += dW;
  1550. X    rstuff->curY += dH;
  1551. X    break;
  1552. X    }
  1553. X
  1554. X    rstuff->winW = newW;
  1555. X    rstuff->winH = newH;
  1556. X
  1557. X    resizeDraw(rstuff);
  1558. X    resizePaintStatus(rstuff);
  1559. X    rstuff->drawn = True;
  1560. X}
  1561. X
  1562. X
  1563. Xvoid
  1564. XresizeDelta(rstuff, action)
  1565. X    ResizeClosure *rstuff;
  1566. X    ResizeAction action;
  1567. X{
  1568. X    int dx, dy;
  1569. X
  1570. X    if (rstuff->mouse)
  1571. X    return;
  1572. X
  1573. X    if (action & RS_ISVERT) {
  1574. X    switch (rstuff->gravity) {
  1575. X    case WestGravity:
  1576. X    case CenterGravity:
  1577. X    case EastGravity:
  1578. X        rstuff->gravity += (action & RS_ISDOWN) ? 3 : -3;
  1579. X        break;
  1580. X    }
  1581. X    } else {
  1582. X    switch (rstuff->gravity) {
  1583. X    case NorthGravity:
  1584. X    case CenterGravity:
  1585. X    case SouthGravity:
  1586. X        rstuff->gravity += (action & RS_ISRIGHT) ? 1 : -1;
  1587. X        break;
  1588. X    }
  1589. X    }
  1590. X
  1591. X    /* generate a delta vector based on which edge is being moved */
  1592. X
  1593. X    dx = ResizeDeltas[action].x;
  1594. X    dy = ResizeDeltas[action].y;
  1595. X
  1596. X    dx *= rstuff->incW;
  1597. X    dy *= rstuff->incH;
  1598. X
  1599. X    resizeMotion(rstuff, rstuff->curX + dx, rstuff->curY + dy);
  1600. X}
  1601. X
  1602. X
  1603. Xstatic int
  1604. XresizeInterposer(dpy, e, w, rstuff)
  1605. X    Display *dpy;
  1606. X    XEvent *e;
  1607. X    WinGeneric *w;
  1608. X    ResizeClosure *rstuff;
  1609. X{
  1610. X    int dx, dy;
  1611. X    unsigned int mask;
  1612. X    SemanticAction action;
  1613. X
  1614. X    switch (e->type) {
  1615. X    case ButtonPress:
  1616. X    if (!FirstButtonDown(e))
  1617. X        break;
  1618. X    switch (ResolveMouseBinding(dpy, e,
  1619. X            ModMaskMap[MOD_CONSTRAIN] | ModMaskMap[MOD_INVERT]))
  1620. X    {
  1621. X    case ACTION_SELECT:
  1622. X        rstuff->mouse = True;
  1623. X        rstuff->curX = rstuff->origX = e->xbutton.x_root;
  1624. X        rstuff->curY = rstuff->origY = e->xbutton.y_root;
  1625. X        if (e->xbutton.state & ModMaskMap[MOD_CONSTRAIN])
  1626. X        rstuff->constraint = EitherConstrained;
  1627. X        if (e->xbutton.state & ModMaskMap[MOD_INVERT])
  1628. X        rstuff->moving = True;
  1629. X
  1630. X        rstuff->gravity = NorthWestGravity;
  1631. X        if (e->xbutton.y_root > rstuff->winY + (rstuff->winH / 2))
  1632. X        rstuff->gravity = SouthWestGravity;
  1633. X        if (e->xbutton.x_root > rstuff->winX + (rstuff->winW / 2))
  1634. X        rstuff->gravity += 2;    /* turns any west into any east */
  1635. X
  1636. X        resizeMotion(rstuff, e->xbutton.x_root, e->xbutton.y_root);
  1637. X        break;
  1638. X    default:
  1639. X        resizeDone(dpy, e, w, rstuff, False);
  1640. X        break;
  1641. X    }
  1642. X    break;
  1643. X    
  1644. X    case ButtonRelease:
  1645. X    if (AllButtonsUp(e))
  1646. X        resizeDone(dpy, e, w, rstuff, True);
  1647. X    break;
  1648. X
  1649. X    case MotionNotify:
  1650. X    if (e->xmotion.same_screen && rstuff->mouse)
  1651. X        resizeMotion(rstuff, e->xmotion.x_root, e->xmotion.y_root);
  1652. X    break;
  1653. X
  1654. X    case KeyPress:
  1655. X    action = FindKeyboardAction(dpy, e);
  1656. X
  1657. X    switch (action) {
  1658. X
  1659. X    case ACTION_STOP:
  1660. X        resizeDone(dpy, e, w, rstuff, False);
  1661. X        break;
  1662. X
  1663. X    case ACTION_UP:        resizeDelta(rstuff, RS_UP);        break;
  1664. X    case ACTION_DOWN:    resizeDelta(rstuff, RS_DOWN);        break;
  1665. X    case ACTION_LEFT:    resizeDelta(rstuff, RS_LEFT);        break;
  1666. X    case ACTION_RIGHT:    resizeDelta(rstuff, RS_RIGHT);        break;
  1667. X    case ACTION_JUMP_UP:    resizeDelta(rstuff, RS_J_UP);        break;
  1668. X    case ACTION_JUMP_DOWN:    resizeDelta(rstuff, RS_J_DOWN);        break;
  1669. X    case ACTION_JUMP_LEFT:    resizeDelta(rstuff, RS_J_LEFT);        break;
  1670. X    case ACTION_JUMP_RIGHT:    resizeDelta(rstuff, RS_J_RIGHT);    break;
  1671. X
  1672. X    case ACTION_EXEC_DEFAULT:
  1673. X        resizeDone(dpy, e, w, rstuff, True);
  1674. X        break;
  1675. X
  1676. X    default:
  1677. X        mask = FindModifierMask(e->xkey.keycode);
  1678. X        if (mask == ModMaskMap[MOD_CONSTRAIN] && rstuff->mouse) {
  1679. X        rstuff->constraint = EitherConstrained;
  1680. X        resizeMotion(rstuff, e->xkey.x_root, e->xkey.y_root);
  1681. X        } else if (mask == ModMaskMap[MOD_INVERT]) {
  1682. X        rstuff->moving = True;
  1683. X        } else {
  1684. X        KeyBeep(dpy, e);
  1685. X        }
  1686. X        break;
  1687. X    }
  1688. X    break;
  1689. X
  1690. X    case KeyRelease:
  1691. X    mask = FindModifierMask(e->xkey.keycode);
  1692. X    if (mask == ModMaskMap[MOD_CONSTRAIN] && rstuff->mouse) {
  1693. X        rstuff->constraint = Unconstrained;
  1694. X        resizeMotion(rstuff, e->xkey.x_root, e->xkey.y_root);
  1695. X    } else if (mask == ModMaskMap[MOD_INVERT])
  1696. X        rstuff->moving = False;
  1697. X    break;
  1698. X
  1699. X    case Expose:
  1700. X    return DISPOSE_DISPATCH;
  1701. X
  1702. X    default:
  1703. X    return DISPOSE_DEFER;
  1704. X    }
  1705. X
  1706. X    return DISPOSE_USED;
  1707. X}
  1708. X
  1709. X
  1710. X
  1711. X/*
  1712. X * Install an interposer for resizing with the mouse.
  1713. X */
  1714. Xvoid
  1715. XUserResizeWin(cli, trigger, corner, callback, cbarg)
  1716. X    Client *cli;
  1717. X    XEvent *trigger;
  1718. X    WhichResize corner;
  1719. X    void (*callback)();
  1720. X    void *cbarg;
  1721. X{
  1722. X    static ResizeClosure rstuff;
  1723. X    XSizeHints *sh = cli->normHints;
  1724. X    Window root = WinRootID(cli->framewin);
  1725. X    Time timestamp;
  1726. X    int frameMinWidth, frameMinHeight;
  1727. X
  1728. X    if (trigger == NULL || trigger->type == KeyPress) {
  1729. X    if (trigger == NULL)
  1730. X        timestamp = CurrentTime;
  1731. X    else
  1732. X        timestamp = trigger->xkey.time;
  1733. X    rstuff.mouse = False;
  1734. X    rstuff.origX = rstuff.curX = cli->framewin->core.x;
  1735. X    rstuff.origY = rstuff.curY = cli->framewin->core.y;
  1736. X    } else {
  1737. X    /* it's a button press */
  1738. X    timestamp = trigger->xbutton.time;
  1739. X    rstuff.mouse = True;
  1740. X    if (trigger->xbutton.state & ModMaskMap[MOD_CONSTRAIN])
  1741. X        rstuff.constraint = EitherConstrained;
  1742. X    else
  1743. X        rstuff.constraint = Unconstrained;
  1744. X
  1745. X    if (trigger->xbutton.state & ModMaskMap[MOD_INVERT])
  1746. X        rstuff.moving = True;
  1747. X    else
  1748. X        rstuff.moving = False;
  1749. X    rstuff.origX = rstuff.curX = trigger->xbutton.x_root;
  1750. X    rstuff.origY = rstuff.curY = trigger->xbutton.y_root;
  1751. X    }
  1752. X
  1753. X    switch (corner) {
  1754. X    case upleft:    rstuff.gravity = NorthWestGravity;    break;
  1755. X    case upright:    rstuff.gravity = NorthEastGravity;    break;
  1756. X    case lowleft:    rstuff.gravity = SouthWestGravity;    break;
  1757. X    case lowright:    rstuff.gravity = SouthEastGravity;    break;
  1758. X    case keyevent:    rstuff.gravity = CenterGravity;        break;
  1759. X    }
  1760. X
  1761. X    /* Grab the pointer to change the cursor and confine to the root window. */
  1762. X    if (XGrabPointer(cli->dpy, root, True,
  1763. X             ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
  1764. X             GrabModeAsync, GrabModeAsync, root,
  1765. X             GRV.ResizePointer, timestamp) != GrabSuccess)
  1766. X    {
  1767. X    ErrorWarning(gettext("failed to grab pointer"));
  1768. X    return;
  1769. X    }
  1770. X
  1771. X    if (XGrabKeyboard(cli->dpy, root, False,
  1772. X              GrabModeAsync, GrabModeAsync,
  1773. X              timestamp) != GrabSuccess)
  1774. X    {
  1775. X    /* note: not fatal */
  1776. X    ErrorWarning(gettext("failed to grab keyboard"));
  1777. X    }
  1778. X
  1779. X    XGrabServer(cli->dpy);
  1780. X
  1781. X    /* Fill in the closure for the interposer. */
  1782. X
  1783. X    rstuff.drawn = False;
  1784. X    rstuff.cli = cli;
  1785. X    rstuff.winX = cli->framewin->core.x;
  1786. X    rstuff.winY = cli->framewin->core.y;
  1787. X    rstuff.winW = cli->framewin->core.width;
  1788. X    rstuff.winH = cli->framewin->core.height;
  1789. X
  1790. X    rstuff.callback = callback;
  1791. X    rstuff.cbarg = cbarg;
  1792. X
  1793. X    /*
  1794. X     * Look at the client's size hints and update the closure appropriately.
  1795. X     */
  1796. X
  1797. X    rstuff.minW = rstuff.minH = 1;
  1798. X    rstuff.maxW = rstuff.maxH = 32767; /* REMIND: max value of signed short */
  1799. X    rstuff.incW = rstuff.incH = 1;
  1800. X    rstuff.minAspect = rstuff.maxAspect = False;
  1801. X    rstuff.baseW = rstuff.baseH = 0;
  1802. X
  1803. X    if (sh != NULL) {
  1804. X    if (sh->flags & PMinSize) {
  1805. X        rstuff.minW = sh->min_width;
  1806. X        rstuff.minH = sh->min_height;
  1807. X    } else if (sh->flags & PBaseSize) {
  1808. X        rstuff.minW = MAX(1,sh->base_width);
  1809. X        rstuff.minH = MAX(1,sh->base_height);
  1810. X    }
  1811. X
  1812. X    if (sh->flags & PMaxSize) {
  1813. X        rstuff.maxW = sh->max_width;
  1814. X        rstuff.maxH = sh->max_height;
  1815. X    }
  1816. X
  1817. X    if ((sh->flags & PResizeInc) &&
  1818. X        sh->width_inc > 0 && sh->height_inc > 0)
  1819. X    {
  1820. X        rstuff.incW = sh->width_inc;
  1821. X        rstuff.incH = sh->height_inc;
  1822. X    }
  1823. X
  1824. X    if (sh->flags & PAspect) {
  1825. X        if (sh->min_aspect.x > 0 && sh->min_aspect.y > 0) {
  1826. X        rstuff.minAspect = True;
  1827. X        rstuff.minAspectX = sh->min_aspect.x;
  1828. X        rstuff.minAspectY = sh->min_aspect.y;
  1829. X        }
  1830. X        if (sh->max_aspect.x > 0 && sh->max_aspect.y > 0) {
  1831. X        rstuff.maxAspect = True;
  1832. X        rstuff.maxAspectX = sh->max_aspect.x;
  1833. X        rstuff.maxAspectY = sh->max_aspect.y;
  1834. X        }
  1835. X    }
  1836. X
  1837. X    if (sh->flags & PBaseSize) {
  1838. X        rstuff.baseW = sh->base_width;
  1839. X        rstuff.baseH = sh->base_height;
  1840. X        rstuff.baseProvided = True;
  1841. X    } else if (sh->flags & PMinSize) {
  1842. X        rstuff.baseW = sh->min_width;
  1843. X        rstuff.baseH = sh->min_height;
  1844. X        rstuff.baseProvided = False;
  1845. X    }
  1846. X    }
  1847. X
  1848. X    /* figure in the size of the frame decorations */
  1849. X
  1850. X    rstuff.borderW
  1851. X    = FrameWidthLeft(cli->framewin) + FrameWidthRight(cli->framewin);
  1852. X    rstuff.borderH
  1853. X    = FrameHeightTop(cli->framewin) + FrameHeightBottom(cli->framewin);
  1854. X
  1855. X    FrameMinSize(cli->framewin, &frameMinWidth, &frameMinHeight);
  1856. X    frameMinWidth -= rstuff.borderW;
  1857. X    frameMinHeight -= rstuff.borderH;
  1858. X    rstuff.minW = MAX(rstuff.minW, frameMinWidth);
  1859. X    rstuff.minH = MAX(rstuff.minH, frameMinHeight);
  1860. X
  1861. X    /* map the geom window and draw the initial outline, if necessary */
  1862. X
  1863. X    if (GRV.ShowResizeGeometry)
  1864. X    rstuff.statuswindow = createStatusWindow(cli->dpy, cli->scrInfo,
  1865. X                         gettext("size: 0000 x 0000"));
  1866. X    else
  1867. X    rstuff.statuswindow = NULL;
  1868. X
  1869. X    if (trigger == NULL || trigger->type == KeyPress) {
  1870. X    resizeDraw(rstuff);
  1871. X    rstuff.drawn = True;
  1872. X    }
  1873. X
  1874. X    resizePaintStatus(&rstuff);
  1875. X
  1876. X    InstallInterposer(resizeInterposer, &rstuff);
  1877. X}
  1878. X
  1879. X
  1880. X/* ===== root bounding box ================================================ */
  1881. X
  1882. X
  1883. Xtypedef struct _rootboxclosure {
  1884. X    int x0, y0;
  1885. X    int x, y;
  1886. X    unsigned int w, h;
  1887. X    WinRoot *rootWin;
  1888. X    Window rootID;
  1889. X    GC rootGC;
  1890. X    void *closure;
  1891. X    void (*callback)();
  1892. X} RootBoxClosure;
  1893. X
  1894. X
  1895. Xstatic int
  1896. XrootBoxInterposer(dpy, event, w, rbc)
  1897. X    Display *dpy;
  1898. X    XEvent *event;
  1899. X    WinGeneric *w;
  1900. X    RootBoxClosure *rbc;
  1901. X{
  1902. X    XEvent nextevent;
  1903. X    register int ex, ey;
  1904. X
  1905. X    switch (event->type) {
  1906. X
  1907. X    case ButtonPress:
  1908. X    return DISPOSE_USED;
  1909. X
  1910. X    case MotionNotify:
  1911. X    /* if the event is off the screen, ignore it */
  1912. X    if (event->xmotion.root != rbc->rootID)
  1913. X        return DISPOSE_USED;
  1914. X
  1915. X    /*
  1916. X     * Motion compression.  If the next event is a MotionNotify,
  1917. X     * ignore this one.
  1918. X     */
  1919. X    if (XEventsQueued(dpy, QueuedAfterReading) > 0 &&
  1920. X        (XPeekEvent(dpy, &nextevent), nextevent.type == MotionNotify))
  1921. X    {
  1922. X        return DISPOSE_USED;
  1923. X    }
  1924. X
  1925. X    /* erase old box */
  1926. X    drawDouble(dpy, rbc->rootID, rbc->rootGC,
  1927. X           rbc->x, rbc->y, rbc->w, rbc->h);
  1928. X
  1929. X    /* update closure with new position */
  1930. X
  1931. X    ex = event->xmotion.x_root;
  1932. X    ey = event->xmotion.y_root;
  1933. X
  1934. X    if (ex > rbc->x0) {
  1935. X        rbc->x = rbc->x0;
  1936. X        rbc->w = ex - rbc->x;
  1937. X    } else {
  1938. X        rbc->x = ex;
  1939. X        rbc->w = rbc->x0 - rbc->x;
  1940. X    }
  1941. X
  1942. X    if (ey > rbc->y0) {
  1943. X        rbc->y = rbc->y0;
  1944. X        rbc->h = ey - rbc->y;
  1945. X    } else {
  1946. X        rbc->y = ey;
  1947. X        rbc->h = rbc->y0 - rbc->y;
  1948. X    }
  1949. X
  1950. X    /* draw new box */
  1951. X
  1952. X    drawDouble(dpy, rbc->rootID, rbc->rootGC,
  1953. X           rbc->x, rbc->y, rbc->w, rbc->h);
  1954. X    return DISPOSE_USED;
  1955. X
  1956. X    case ButtonRelease:
  1957. X    if (!AllButtonsUp(event))
  1958. X        return DISPOSE_USED;
  1959. X    break;
  1960. X
  1961. X    case KeyPress:
  1962. X    if (FindKeyboardAction(dpy, event) != ACTION_STOP) {
  1963. X        KeyBeep(dpy,event);
  1964. X        return DISPOSE_USED;
  1965. X    }
  1966. X    break;
  1967. X
  1968. X    default:
  1969. X    return DISPOSE_DEFER;
  1970. X    }
  1971. X
  1972. X    /*
  1973. X     * erase outline, let go of server, call the callback
  1974. X     */
  1975. X    drawDouble(dpy, rbc->rootID, rbc->rootGC,
  1976. X           rbc->x, rbc->y, rbc->w, rbc->h);
  1977. X
  1978. X    XUngrabServer(dpy);
  1979. X    XUngrabPointer(dpy, CurrentTime);
  1980. X    XUngrabKeyboard(dpy, CurrentTime);
  1981. X
  1982. X    UninstallInterposer();
  1983. X
  1984. X    (*rbc->callback)(dpy, rbc->rootWin, rbc->x, rbc->y, rbc->w, rbc->h,
  1985. X        event->xbutton.time, rbc->closure);
  1986. X
  1987. X    return DISPOSE_USED;
  1988. X}
  1989. X
  1990. X
  1991. X/*
  1992. X * TraceRootBox -- trace an XOR box with the initial point specified
  1993. X *    by pEvent, which is assumed to be a ButtonPress event.  Call the 
  1994. X *    callback function when done.
  1995. X */
  1996. Xvoid
  1997. XTraceRootBox(dpy, winInfo, pEvent, callback, closure)
  1998. XDisplay    *dpy;
  1999. XWinRoot *winInfo;
  2000. XXEvent    *pEvent;
  2001. Xvoid    (*callback)();
  2002. Xvoid    *closure;
  2003. X{
  2004. X    static RootBoxClosure rbc;
  2005. X    Window rootID = WinRootID(winInfo);
  2006. X
  2007. X    /* Change and confine the cursor. */
  2008. X    if (XGrabPointer(dpy, rootID, True,
  2009. X        ButtonReleaseMask | PointerMotionMask,
  2010. X        GrabModeAsync, GrabModeAsync, rootID, GRV.BasicPointer,
  2011. X        pEvent->xbutton.time) != GrabSuccess)
  2012. X    {
  2013. X        ErrorWarning(gettext("failed to grab pointer"));
  2014. X        return;
  2015. X    }
  2016. X
  2017. X    if (XGrabKeyboard(dpy, rootID, False, GrabModeAsync, GrabModeAsync,
  2018. X              pEvent->xbutton.time) != GrabSuccess)
  2019. X    {
  2020. X        /* note: not fatal */
  2021. X        ErrorWarning(gettext("failed to grab keyboard"));
  2022. X    }
  2023. X
  2024. X    rbc.x = rbc.x0 = pEvent->xbutton.x_root;
  2025. X    rbc.y = rbc.y0 = pEvent->xbutton.y_root;
  2026. X    rbc.w = rbc.h = 0;
  2027. X    rbc.rootWin = winInfo;
  2028. X    rbc.rootID = rootID;
  2029. X    rbc.rootGC = WinGC(winInfo, ROOT_GC);
  2030. X    rbc.callback = callback;
  2031. X    rbc.closure = closure;
  2032. X
  2033. X    /* Grab the server, then draw the initial outline. */
  2034. X    XGrabServer(dpy);
  2035. X    drawDouble(dpy, rootID, WinGC(winInfo, ROOT_GC),
  2036. X           rbc.x, rbc.y, 0, 0);
  2037. X
  2038. X    InstallInterposer(rootBoxInterposer, &rbc);
  2039. X    return;
  2040. X}
  2041. END_OF_FILE
  2042. if test 48613 -ne `wc -c <'moveresize.c'`; then
  2043.     echo shar: \"'moveresize.c'\" unpacked with wrong size!
  2044. fi
  2045. # end of 'moveresize.c'
  2046. fi
  2047. echo shar: End of archive 4 \(of 21\).
  2048. cp /dev/null ark4isdone
  2049. MISSING=""
  2050. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ; do
  2051.     if test ! -f ark${I}isdone ; then
  2052.     MISSING="${MISSING} ${I}"
  2053.     fi
  2054. done
  2055. if test "${MISSING}" = "" ; then
  2056.     echo You have unpacked all 21 archives.
  2057.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2058. else
  2059.     echo You still need to unpack the following archives:
  2060.     echo "        " ${MISSING}
  2061. fi
  2062. ##  End of shell archive.
  2063. exit 0
  2064. --
  2065. Molecular Simulations, Inc.             mail: dcmartin@postgres.berkeley.edu
  2066. 796 N. Pastoria Avenue                  uucp: uwvax!ucbvax!dcmartin
  2067. Sunnyvale, California 94086             at&t: 408/522-9236
  2068.